package com.eastfair.tag.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.code.ExceptionCode;
import com.eastfair.core.utils.ConvertUtil;
import com.eastfair.mongocrud.dao.impl.BaseDaoImpl;
import com.eastfair.tag.entity.Tag;
import com.eastfair.tag.entity.TagResource;
import com.eastfair.tag.entity.TagTarget;
import com.eastfair.tag.enumeration.TagResourceTypeEnum;
import com.eastfair.tag.service.BaseTagTargetService;
import com.eastfair.tag.service.TagResourceService;
import com.eastfair.tag.service.TagService;
import com.eastfair.tag.vo.TagResourceVO;
import com.eastfair.tag.vo.TagVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 *
 * </p>
 *
 * @author zjn
 * @date 2022-03-11
 */
@Slf4j
@Service
public class BaseTagTargetServiceImpl<T extends TagTarget> implements BaseTagTargetService<T> {

    @Autowired
    private TagService tagService;
    @Autowired
    private TagResourceService tagResourceService;

    @Override
    public R<Boolean> saveTagTarget(T T, BaseDaoImpl baseTagTargetMongoDao) {
        if (checkBaseRequestParams(T) || CollectionUtil.isEmpty(T.getTagIdList())) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        // 删除原有关联关系
        R<Boolean> delFlag = delTargetTagByResourceType(T, Arrays.asList(TagResourceTypeEnum.DEFAULT), baseTagTargetMongoDao);
        if (!delFlag.getIsSuccess()) {
            return delFlag;
        }

        // 绑定新关联关系
        R<Boolean> saveFlag = saveTargetTag(T, baseTagTargetMongoDao);
        if (!saveFlag.getIsSuccess()) {
            return saveFlag;
        }

        return R.successDef();
    }

    @Override
    public R<Boolean> saveTagTargetByResourceType(T T, BaseDaoImpl baseTagTargetMongoDao) {
        if (checkBaseRequestParams(T) || CollectionUtil.isEmpty(T.getTagResourceDTOList())) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        // 获取资源类型
        List<TagResourceTypeEnum> tagResourceTypeList = T.getTagResourceDTOList().stream().map(TagResource::getResourceType).collect(Collectors.toList())
                .stream().distinct().collect(Collectors.toList());
        if (CollectionUtil.isEmpty(tagResourceTypeList)) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        // 删除原有关联关系
        R<Boolean> delFlag = delTargetTagByResourceType(T, tagResourceTypeList, baseTagTargetMongoDao);
        if (!delFlag.getIsSuccess()) {
            return delFlag;
        }

        // 绑定新关联关系
        R<Boolean> saveFlag = saveTargetTagByResource(T, baseTagTargetMongoDao);
        if (!saveFlag.getIsSuccess()) {
            return saveFlag;
        }

        return R.successDef();
    }

    /**
     * 删除标签与主体的关系
     *
     * @param T
     * @param tagResourceTypeList
     */
    private R<Boolean> delTargetTagByResourceType(T T, List<TagResourceTypeEnum> tagResourceTypeList, BaseDaoImpl baseTagTargetMongoDao) {

        if (checkBaseRequestParams(T) || CollectionUtil.isEmpty(tagResourceTypeList)) {
            R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        for (TagResourceTypeEnum tagResourceType : tagResourceTypeList) {
            TagTarget tagTarget = TagTarget.builder().projectId(ContextUtil.getProjectId())
                    .exhibitionId(ContextUtil.getExhibitionId())
                    .subjectType(T.getSubjectType())
                    .subjectId(T.getSubjectId())
                    .tagResourceType(tagResourceType).build();
            T tagTarget1 = (T) tagTarget;
            baseTagTargetMongoDao.deleteOfParam((T) tagTarget);
        }
        return R.successDef();
    }

    private R<Boolean> saveTargetTag(T T, BaseDaoImpl baseTagTargetMongoDao) {
        if (checkBaseRequestParams(T)) {
            R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        // 获取所有标签
        List<Tag> tagList = tagService.listByIds(T.getTagIdList());
        if (CollectionUtil.isEmpty(tagList)) {
            R.fail(ExceptionCode.ERROR_NULL_ID);
        }

        // 直接挂接实体与标签的关系
        List<T> param = new ArrayList<>();
        tagList.forEach(tag -> {
            T.setProjectId(ContextUtil.getProjectId());
            T.setExhibitionId(ContextUtil.getExhibitionId());
            T.setTagResourceType(TagResourceTypeEnum.DEFAULT);
            T.setTagId(tag.getId());
            T.setTagName(tag.getName());
            T.setTagEnName(tag.getEnName());
            param.add(T);
        });

        baseTagTargetMongoDao.addBatch(param);
        return R.successDef();
    }

    private R<Boolean> saveTargetTagByResource(T T, BaseDaoImpl baseTagTargetMongoDao) {
        if (checkBaseRequestParams(T) || CollectionUtil.isEmpty(T.getTagResourceDTOList())) {
            R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        // 获取所有标签
        R<List<TagResourceVO>> tagResourceResult = tagResourceService.getTagResourceRelationList(T.getTagResourceDTOList());
        if (!tagResourceResult.getIsSuccess()) {
            return R.fail(tagResourceResult.getMsg());
        }

        // 直接挂接实体与标签的关系
        List<T> param = new ArrayList<>();
        Set<Long> tagIdList = new HashSet<>();
        for (TagResourceVO tagResourceVO : tagResourceResult.getData()) {
            if (CollectionUtil.isEmpty(tagResourceVO.getTagVOList())) {
                continue;
            }
            for (TagVO tagVO : tagResourceVO.getTagVOList()) {
                if (!tagIdList.contains(tagVO.getId())) {
                    T.setProjectId(ContextUtil.getProjectId());
                    T.setExhibitionId(ContextUtil.getExhibitionId());
                    T.setTagResourceType(tagResourceVO.getResourceType());
                    T.setTagId(tagVO.getId());
                    T.setTagName(tagVO.getName());
                    T.setTagEnName(tagVO.getEnName());
                    param.add(T);
                    tagIdList.add(tagVO.getId());
                }
            }
        }

        baseTagTargetMongoDao.addBatch(param);
        return R.successDef();
    }

    @Override
    public R<List<Object>> getTargetTagList(T T, BaseDaoImpl baseTagTargetMongoDao) {
        if (checkBaseRequestParams(T)) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }
        TagTarget tagTarget = TagTarget.builder().subjectType(T.getSubjectType()).subjectId(T.getSubjectId()).build();
        return R.success(ConvertUtil.convertList(baseTagTargetMongoDao.find((T) tagTarget), Object.class));
    }

    private Boolean checkBaseRequestParams(T T) {
        if (Objects.isNull(T)
                || Objects.isNull(T.getSubjectType())
                || Objects.isNull(T.getSubjectId())) {
            return true;
        }
        return false;
    }
}
